﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace NeuralNetwork.Generic
{
    public class Factory<Product>
    {
        private Dictionary<string, Type> map = new Dictionary<string, Type>();

        public Factory()
        {
            Type[] types = Assembly.GetAssembly(typeof(Product)).GetTypes();
            foreach (Type type in types)
            {
                if (!typeof(Product).IsAssignableFrom(type)) 
                {
                    continue; 
                }
                
                map.Add(type.Name.ToUpper(), type);
            }
        }

        public Product Make(string productName, params object[] args)
        {
            Type t = map[productName.ToUpper()];
            return (Product)Activator.CreateInstance(t, args);
        }

        public Product Make(string productName, string templateType, params object[] args)
        {
            Type t = map[productName.ToUpper()];            
            Type[] types = new Type[]{Type.GetType(templateType)};
            Type gt = t.MakeGenericType(types);
            return (Product)Activator.CreateInstance(gt, args);
        }

        public List<string> List()
        {
            List<string> knownTypes = new List<string>();
            
            Type[] types = Assembly.GetAssembly(typeof(Product)).GetTypes();
            foreach (Type type in types)
            {
                if (!typeof(Product).IsAssignableFrom(type) || type.IsAbstract)
                {
                    continue;
                }
                knownTypes.Add(type.Name);
            }

            return knownTypes;
        }
    }
}
